package pl.un4giv3n.mightvsmagic.action;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.Query;

import pl.un4giv3n.mightvsmagic.entity.Action;
import pl.un4giv3n.mightvsmagic.entity.ActionType;
import pl.un4giv3n.mightvsmagic.entity.ActivityDetails;
import pl.un4giv3n.mightvsmagic.entity.ActivityType;
import pl.un4giv3n.mightvsmagic.entity.FightReport;
import pl.un4giv3n.mightvsmagic.entity.ItemStub;
import pl.un4giv3n.mightvsmagic.entity.Reward;
import pl.un4giv3n.mightvsmagic.entity.Round;
import pl.un4giv3n.mightvsmagic.entity.User;
import pl.un4giv3n.mightvsmagic.entity.UserActivity;
import pl.un4giv3n.mightvsmagic.utils.ActionUtil;
import pl.un4giv3n.mightvsmagic.utils.ActivityLogUtil;
import pl.un4giv3n.mightvsmagic.utils.FightUtil;
import pl.un4giv3n.mightvsmagic.utils.FormatterUtil;

/**
 * @author andrzejewskia
 * performs attack on another user
 */
public class FightAction extends PersistenceAction {

	private static final long serialVersionUID = 1L;
	/**
	 * defending user login this is populated by struts from request param
	 */
	private String defenderLogin;
	/**
	 * session/attacking user
	 */
	private User user;
	/**
	 * defenfing user
	 */
	private User defender;
	/**
	 * fight result
	 */
	private FightReport fight;
	/**
	 * current action performed by attacking user
	 */
	private Action currentAction;

	/*
	 * (non-Javadoc)
	 * 
	 * @see pl.un4giv3n.mightvsmagic.action.PersistenceAction#execute()
	 */
	@SuppressWarnings("unchecked")
	@Override
	public String execute() {
		EntityManager entityManager = getEntityManager();
		user = getSessionUser(entityManager);
		if (user == null) {
			addActionError("Zaloguj się");
			entityManager.close();
			return LOGIN;
		}
		EntityTransaction transaction = entityManager.getTransaction();
		transaction.begin();
		Query query = entityManager.createNamedQuery("find.user.by.login");
		query.setParameter("login", defenderLogin);
		List resultList = query.getResultList();
		if(resultList == null || resultList.isEmpty()){
			addActionError("Wybrany gracz nie istnieje");
			transaction.rollback();
			return ERROR;
		}
		defender = (User) resultList.get(0);
		if(!validateData(entityManager)){
			transaction.rollback();
			return ERROR;
		}
		fight = FightUtil.fight(user, defender);
		entityManager.persist(fight);
		for (Round round : fight.getRounds()) {
			entityManager.persist(round);
		}
		entityManager.persist(fight.getAttacker());
		for (ItemStub itemStub : fight.getAttacker().getItems()) {
			entityManager.persist(itemStub);
		}
		entityManager.persist(fight.getDefender());
		for (ItemStub itemStub : fight.getDefender().getItems()) {
			entityManager.persist(itemStub);
		}
		Reward reward = fight.getReward();
		String winnerLogin = fight.getWinner();
		User winner = null;
		User looser = null;
		if (winnerLogin.equals(user.getLogin())) {
			winner = user;
			looser = defender;
		} else {
			winner = defender;
			looser = user;
		}
		winner.addGold(reward.getRewardedGold());
		winner.addFightExp(reward.getRewardedFightExp());
		winner.addMagicExp(reward.getRewardedMagicExp());
		looser.addFightExp(fight.getLooserBonusFightExp());
		looser.addMagicExp(fight.getLooserBonusMagicExp());
		looser.removeGold(reward.getRewardedGold());
		winner.setLastFightTime(fight.getFightTime());
		looser.setLastFightTime(fight.getFightTime());
		user.setCurrentAction(new Action(ActionType.FIGHT, Reward.NO_REWARD));
		winner.resetHp();
		looser.resetHp();
		entityManager.merge(winner);
		entityManager.merge(looser);
		String desc = " Atak na gracza: "+ defender.toString() +" zwycięzca="+winner.getLogin()+ " wygrana="+reward.getRewardedGold();
		UserActivity activity = ActivityLogUtil.createActivity(ActivityType.ATTACK_OTHER_USER, user.getId(), new ActivityDetails(desc, fight.getId()));
		entityManager.persist(activity);
		desc = " Zaatakowany przez gracza: "+ user.toString() +" zwycięzca="+winner.getLogin()+  " wygrana="+reward.getRewardedGold();
		UserActivity defactivity = ActivityLogUtil.createActivity(ActivityType.WAS_ATTACKED_BY_USER, defender.getId(),new ActivityDetails(desc, fight.getId()));
		entityManager.persist(defactivity);
		entityManager.flush();
		transaction.commit();
		entityManager.close();
		return SUCCESS;
	}

	private boolean validateData(EntityManager entityManager) {
		boolean valid = true;
		if (!FightUtil.canAttack(user)) {
			String msg = "Nie możesz jeszcze atakować.";
			if(ActionUtil.actionEnded(user.getCurrentAction(), user)){
				msg+=" Musisz najpierw zakończyc poprzednią akcję.";
			}else{
				msg+=" Spróbuj ponownie za około "
				+ ActionUtil.getActionEnd(user.getCurrentAction(), user);
			}
			addActionError(msg);
			currentAction = user.getCurrentAction();
			valid = false;
		}
		if (defender.equals(user)) {
			addActionError("Nie możesz zaatakowac siebie!");
			valid = false;
		}
		if (!FightUtil.canDefend(defender)) {
			addActionError("Wybrany gracz walczył w ciągu ostatnich "+FightUtil.SF_TIME_STR+" min i nie może być zaatakowany");
			valid = false;
		}
		if(!FightUtil.canFightAgain(user, defender, entityManager)){
			addActionError("Nie możesz zaatakować tego gracza, ponieważ walczyliście w ciągu ostatnich "+FightUtil.MIN_DUR_FOR_SAME_PLAYERS_STR+" min.");
			valid = false;
		}
		return valid;
	}

	// this is the data for page fight-report.jsp
	public FightReport getFight() {
		return fight;
	}

	public String getAttackerDamage() {
		return FormatterUtil.formatDamage(FightUtil.getAttackerDamage(fight));
	}

	public String getDefenderDamage() {
		return FormatterUtil.formatDamage(FightUtil.getDefenderDamage(fight));
	}
	public List<ItemStub> getDefenderEquipedItems(){
		return fight.getDefender().getItems();
	}
	public List<ItemStub> getAttackerEquipedItems(){
		return fight.getAttacker().getItems();
	}
	public String getActionEndString(){
		if(currentAction != null){
			return ActionUtil.getActionEndDate(currentAction, user);
		}
		return "";
	}

	public String getDefenderLogin() {
		return defenderLogin;
	}

	public void setDefenderLogin(String defenderLogin) {
		this.defenderLogin = defenderLogin;
	}
	

}
